'use strict';

const { listDir, pathJoin } = require('../util/fs');
const { assert } = require('../util/assert');

// Source files included in configure and dist.
// Except duktape.h.in which needs replacement processing.
const sourceFiles = [
    'duk_alloc_default.c',
    'duk_api_internal.h',
    'duk_api_stack.c',
    'duk_api_heap.c',
    'duk_api_buffer.c',
    'duk_api_call.c',
    'duk_api_codec.c',
    'duk_api_compile.c',
    'duk_api_bytecode.c',
    'duk_api_inspect.c',
    'duk_api_memory.c',
    'duk_api_object.c',
    'duk_api_random.c',
    'duk_api_readable.c',
    'duk_api_string.c',
    'duk_api_time.c',
    'duk_api_debug.c',
    'duk_bi_array.c',
    'duk_bi_boolean.c',
    'duk_bi_buffer.c',
    'duk_bi_cbor.c',
    'duk_bi_date.c',
    'duk_bi_date_unix.c',
    'duk_bi_date_windows.c',
    'duk_bi_duktape.c',
    'duk_bi_encoding.c',
    'duk_bi_error.c',
    'duk_bi_function.c',
    'duk_bi_global.c',
    'duk_bi_json.c',
    'duk_bi_math.c',
    'duk_bi_number.c',
    'duk_bi_object.c',
    'duk_bi_performance.c',
    'duk_bi_pointer.c',
    'duk_bi_protos.h',
    'duk_bi_reflect.c',
    'duk_bi_regexp.c',
    'duk_bi_string.c',
    'duk_bi_promise.c',
    'duk_bi_proxy.c',
    'duk_bi_symbol.c',
    'duk_bi_thread.c',
    'duk_bi_thrower.c',
    'duk_dblunion.h',
    'duk_debug_fixedbuffer.c',
    'duk_debug.h',
    'duk_debug_macros.c',
    'duk_debug_vsnprintf.c',
    'duk_debugger.c',
    'duk_debugger.h',
    'duk_error_augment.c',
    'duk_error.h',
    'duk_error_longjmp.c',
    'duk_error_macros.c',
    'duk_error_misc.c',
    'duk_error_throw.c',
    'duk_fltunion.h',
    'duk_forwdecl.h',
    'duk_harray.h',
    'duk_hboundfunc.h',
    'duk_hbuffer_alloc.c',
    'duk_hbuffer_assert.c',
    'duk_hbuffer.h',
    'duk_hbuffer_ops.c',
    'duk_hbufobj.h',
    'duk_hbufobj_misc.c',
    'duk_hcompfunc.h',
    'duk_heap_alloc.c',
    'duk_heap.h',
    'duk_heap_hashstring.c',
    'duk_heaphdr.h',
    'duk_heaphdr_assert.c',
    'duk_heap_finalize.c',
    'duk_heap_markandsweep.c',
    'duk_heap_memory.c',
    'duk_heap_misc.c',
    'duk_heap_refcount.c',
    'duk_heap_stringcache.c',
    'duk_heap_stringtable.c',
    'duk_hnatfunc.h',
    'duk_hobject_alloc.c',
    'duk_hobject_array.c',
    'duk_hobject_assert.c',
    'duk_hobject_class.c',
    'duk_hobject.h',
    'duk_hobject_lookup.c',
    'duk_hobject_misc.c',
    'duk_hobject_pc2line.c',
    'duk_hobject_props.c',
    'duk_hobject_proxy.c',
    'duk_hobject_resize.c',
    'duk_hproxy.h',
    'duk_hstring.h',
    'duk_hstring_assert.c',
    'duk_hstring_misc.c',
    'duk_hthread_alloc.c',
    'duk_hthread_builtins.c',
    'duk_hthread.h',
    'duk_hthread_misc.c',
    'duk_hthread_stacks.c',
    'duk_henv.h',
    'duk_internal.h',
    'duk_jmpbuf.h',
    'duk_exception.h',
    'duk_js_arith.c',
    'duk_js_bytecode.h',
    'duk_js_call.c',
    'duk_js_compiler.c',
    'duk_js_compiler.h',
    'duk_js_executor.c',
    'duk_js.h',
    'duk_json.h',
    'duk_js_ops.c',
    'duk_js_prop.c',
    'duk_js_var.c',
    'duk_lexer.c',
    'duk_lexer.h',
    'duk_numconv.c',
    'duk_numconv.h',
    'duk_prop_defown.c',
    'duk_prop_delete.c',
    'duk_prop_enum.c',
    'duk_prop_get.c',
    'duk_prop_getown.c',
    'duk_prop.h',
    'duk_prop_has.c',
    'duk_prop_ownpropkeys.c',
    'duk_prop_set.c',
    'duk_prop_util.c',
    'duk_refcount.h',
    'duk_regexp_compiler.c',
    'duk_regexp_executor.c',
    'duk_regexp.h',
    'duk_tval.c',
    'duk_tval.h',
    'duk_unicode.h',
    'duk_unicode_support.c',
    'duk_unicode_tables.c',
    'duk_unicode_wtf8.c',
    'duk_util.h',
    'duk_util_bitdecoder.c',
    'duk_util_bitencoder.c',
    'duk_util_hashbytes.c',
    'duk_util_tinyrandom.c',
    'duk_util_bufwriter.c',
    'duk_util_double.c',
    'duk_util_cast.c',
    'duk_util_memory.c',
    'duk_util_memrw.c',
    'duk_util_misc.c',
    'duk_selftest.c',
    'duk_selftest.h',
    'duk_strings.h',
    'duk_replacements.c',
    'duk_replacements.h'
];
exports.sourceFiles = sourceFiles;

// Select source files for amalgamation, taking into consideration some
// ordering constraints.
function selectCombinedSources(srcArg, srcDirectory) {
    // These files must appear before the alphabetically sorted
    // ones so that static variables get defined before they're
    // used.  We can't forward declare them because that would
    // cause C++ issues (see GH-63).  When changing, verify by
    // compiling with g++.
    var handpick = [
        'duk_unicode_tables.c',
        'duk_replacements.c',
        'duk_debug_macros.c',
        'duk_builtins.c',
        'duk_error_macros.c',
        'duk_unicode_support.c',
        'duk_util_memrw.c',
        'duk_util_misc.c',
        'duk_hobject_class.c'
    ];

    // These files are ignored, e.g. autogenerated C files which are
    // pulled in using #includes.  This is now unnecessary because
    // generated files amalgamated only via #includes are placed in
    // a separate directory and the file list is given explicitly.
    var ignore = [];
    /*
    var ignore = [
        'duk_unicode_caseconv.c',
        'duk_unicode_caseconv.h',
        'duk_unicode_re_canon_lookup.c',
        'duk_unicode_re_canon_lookup.h',
        'duk_unicode_re_canon_bitmap.c',
        'duk_unicode_re_canon_bitmap.h',
        'duk_unicode_ws.c',
        'duk_unicode_ws.h',
        'duk_unicode_ids_noa.c',
        'duk_unicode_ids_noa.h',
        'duk_unicode_ids_noabmp.c',
        'duk_unicode_ids_noabmp.h',
        'duk_unicode_ids_m_let_noa.c',
        'duk_unicode_ids_m_let_noa.h',
        'duk_unicode_ids_m_let_noabmp.c',
        'duk_unicode_ids_m_let_noabmp.h',
        'duk_unicode_idp_m_ids_noa.c',
        'duk_unicode_idp_m_ids_noa.h',
        'duk_unicode_idp_m_ids_noabmp.c',
        'duk_unicode_idp_m_ids_noabmp.h'
    ];
    */

    // Get raw .c file list, either given by caller or listing a directory.
    var rawFiles = [];
    if (Array.isArray(srcArg)) {
        rawFiles = rawFiles.concat(srcArg);
    } else {
        listDir(srcArg).sort().forEach((fn) => {
            if (rawFiles.indexOf(fn) >= 0) {
                return;
            }
            rawFiles.push(fn);
        });
    }
    rawFiles = rawFiles.filter((fn) => {
        return fn.endsWith('c') && ignore.indexOf(fn) < 0;
    }).sort();

    // Handpick specific files first.
    var files = [];
    handpick.forEach((fn) => {
        let idx = rawFiles.indexOf(fn);
        assert(idx >= 0);
        void rawFiles.splice(idx, 1);
        files.push(fn);
    });

    // Append remaining files in sorted order.
    files = files.concat(rawFiles);

    var res = files.map((fn) => pathJoin(srcDirectory, fn));
    return res;
}
exports.selectCombinedSources = selectCombinedSources;
